/*
    Developer: John Archer (john.archer.jpa@gmail.com)
 
    This file is part of VTBuilder.

    VTBuilder is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License.

    VTBuilder is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with VTBuilder.  If not, see <http://www.gnu.org/licenses/>.
 */

package core.tasks.pack;

import gui.processor.Processor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.ListIterator;
import java.util.concurrent.CountDownLatch;

public class DNPack extends Thread{
    ArrayList <String> pIn;
    public ArrayList <String> pOut;
    private final CountDownLatch stopLatch;
    private Processor p;
    
    public DNPack(CountDownLatch stopLatch, ArrayList <String> pIn, Processor p){
        this.stopLatch = stopLatch;
        this.pIn = pIn;
        this.p = p;
    }
    
    public void run(){
        getDeNovo();
        stopLatch.countDown();
    }
    
    
    public void getDeNovo(){
        HashMap<String, ArrayList<Integer>> lib = new HashMap<String, ArrayList<Integer>> ();
    	ArrayList <String> dnSeqs = new ArrayList<String>();
        String cur;TRHit ht;int ewin;int hts;int swin;String dna;
        boolean added;int df;int mD;int mF;int freq;
        TRHit [] siteHt;ArrayList <TRHit> [] sd;
        HashMap <Integer, Integer> hsh = new HashMap<Integer, Integer>(250);
        do{
            cur = pIn.remove(0);
            lib.clear();
            for (int loc = 0; loc < (cur.length() - 10); loc++) {
                if (lib.containsKey(cur.substring(loc, loc + 10))) {lib.get(cur.substring(loc, loc + 10)).add(loc);} 
                else {lib.put(cur.substring(loc, loc + 10),  new ArrayList<Integer>(Arrays.asList(loc)));}
            }
            do{
                added=false;
                ListIterator<String> it = pIn.listIterator();
                outter: while(it.hasNext()) {
                    mD=0;mF=0;
                    ht = null;
                    dna = it.next();
                    siteHt = new TRHit[dna.length()-10];
                    sd = new ArrayList[siteHt.length];
                    hsh.clear();
                    for(int r=0; r<sd.length; r++){sd[r] = new ArrayList <TRHit>();}
                    for (int l=0; l < siteHt.length; l++) {
                        if (lib.containsKey(dna.substring(l, l + 10))) {
                            for (int t : lib.get(dna.substring(l, l + 10))){
                                sd[l].add(new TRHit(t, l, df = t - l));
                                if(hsh.get(df)==null){hsh.put(df, 1);}
                                else{
                                    freq = hsh.get(df)+1;
                                    if(freq>mF){mF=freq;mD=df;}
                                    hsh.put(df, freq);
                                }
                            }
                        }
                    }
                    
                    ewin = hts = swin = 0;

                    if(mF > 20){
                        int count = 0;
                        for (ArrayList <TRHit> c : sd) {     
                            inner: for (TRHit i : c) {
                                if(c!=null && i.df == mD){
                                    siteHt[count] = i;
                                    break inner;
                                }
                            }
                            count++;
                        }
                        //window is 100
                        while(ewin<100 && ewin<siteHt.length){if(siteHt[ewin++]!=null){hts++;}}
                        //90 out of window of 100 is 90%
                        if(hts>90){
                            while(siteHt[swin++]==null);
                            ht = siteHt[swin];
                        }
                        else{
                            swin = 1;ewin = 101;
                            inner: while(ewin<siteHt.length){
                                if(siteHt[ewin]!=null && siteHt[swin]==null){
                                    if(++hts>90){
                                        while(siteHt[swin++]==null);
                                        ht = siteHt[swin];
                                        break inner;
                                    }
                                }
                                else if(siteHt[ewin]==null && siteHt[swin]!=null){hts--;}
                                ewin++;swin++;
                            }
                        }
                        if(ht!=null){
                            if((ht.tl < ht.rl)){
                                cur = dna.substring(0, ht.rl) + "" + cur.substring(ht.tl);                           
                                lib.clear();
                                for (int loc = 0; loc < (cur.length() - 10); loc++) {
                                    if (lib.containsKey(cur.substring(loc, loc + 10))) {lib.get(cur.substring(loc, loc + 10)).add(loc);} 
                                    else {lib.put(cur.substring(loc, loc + 10),  new ArrayList<Integer>(Arrays.asList(loc)));}
                                }
                                it.remove();
                                added = true;
                                break outter;
                            }
                            else if((cur.length() - ht.tl < dna.length() - ht.rl)){
                                cur = cur.substring(0, ht.tl) + "" + dna.substring(ht.rl);
                                lib.clear();
                                for (int loc = 0; loc < (cur.length() - 10); loc++) {
                                    if (lib.containsKey(cur.substring(loc, loc + 10))) {lib.get(cur.substring(loc, loc + 10)).add(loc);} 
                                    else {lib.put(cur.substring(loc, loc + 10),  new ArrayList<Integer>(Arrays.asList(loc)));}
                                }
                                it.remove();
                                added = true;
                                break outter;
                            }
                            else{
                                it.remove();
                            }     
                        }
                    }
                }
            }while(added);
            dnSeqs.add(cur);
        }while(pIn.size()>0);
        pOut = dnSeqs; 
        pIn = null;
    }
}